package com.dongrj.framework.core.utils;

import com.dongrj.framework.core.exception.SystemException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapType;
import com.jayway.jsonpath.JsonPath;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;


@Slf4j
public final class JsonUtils {

    /**
     * 公用的Json解析类
     */
    private final static ObjectMapper commonObjectMapper = new ObjectMapper();

    static {
        commonObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /**
     * 对象转Json
     *
     * @param object 对象
     */
    public static String toJson(Object object) {
        return toJson(commonObjectMapper, object);
    }


    /**
     * @param json Json字符串
     */
    public static <T> T toBean(String json, Type type) {
        try {
            JavaType javaType = toJavaType(type);
            return commonObjectMapper.readValue(json, javaType);
        } catch (JsonProcessingException e) {
            throw new SystemException(String.format("Json:%s解析异常!", json), e);
        }
    }


    /**
     * @param json   Json字符串
     * @param tClass 转的Class类型
     */
    public static <T> T toBean(String json, Class<T> tClass) {
        try {
            return commonObjectMapper.readValue(json, tClass);
        } catch (JsonProcessingException e) {
            throw new SystemException(String.format("Json:%s解析异常!", json), e);
        }
    }

    public static <T> T toBean(String json, TypeReference<T> type) {
        try {
            return commonObjectMapper.readValue(json, type);
        } catch (IOException e) {
            throw new SystemException(String.format("Json:%s解析异常!", json), e);
        }
    }


    public static <T> List<T> toList(String json, Class<T> tClass) {
        try {
            CollectionType collectionType = toListType(tClass);
            return commonObjectMapper.readValue(json, collectionType);
        } catch (IOException e) {
            throw new SystemException(String.format("Json:%s解析异常!", json), e);
        }
    }

    public static <K, V> Map<K, V> toMap(String json, Class<K> kClass, Class<V> vClass) {
        try {
            MapType mapType = commonObjectMapper.getTypeFactory().constructMapType(Map.class, kClass, vClass);
            return commonObjectMapper.readValue(json, mapType);
        } catch (IOException e) {
            throw new SystemException(String.format("Json:%s解析异常!", json), e);
        }
    }

    public static Map<String, Object> toMap(String json) {
        return toMap(json, String.class, Object.class);
    }

    /**
     * 根据Key获取Value
     *
     * @param json Json字符串
     * @param key  键集合
     */
    public static String getValue(String json, String key) {
        String[] split = key.split("\\.");
        return getValue(json, split);
    }

    /**
     * 获取数组Json节点
     *
     * @param jsonNode 父节点
     * @param key      key
     */
    private static JsonNode getArrayJsonNode(JsonNode jsonNode, String key) {
        if (jsonNode.isArray()) {
            ArrayNode arrayNode = (ArrayNode) jsonNode;
            int arrayKeyValue = getArrayKeyValue(key);
            return arrayNode.get(arrayKeyValue);
        } else {
            throw new RuntimeException("Key:" + key + "的值不是数组类型!");
        }
    }

    /**
     * 根据Key获取Value
     *
     * @param json Json字符串
     * @param keys 键的集合
     * @see https://github.com/json-path/JsonPath
     */
    public static String getValue(String json, String... keys) {
        JsonNode root = getRoot(json);
        JsonNode jsonNode = null;
        for (String key : keys) {
            if (jsonNode == null) {
                if (keyIsArray(key)) {
                    jsonNode = getArrayJsonNode(root, key);
                } else {
                    jsonNode = root.path(key);
                }
            } else {
                if (keyIsArray(key)) {
                    jsonNode = getArrayJsonNode(jsonNode, key);
                } else {
                    jsonNode = jsonNode.path(key);
                }
            }
        }
        if (jsonNode == null) {
            return null;
        }
        if (jsonNode.isTextual()) {
            return jsonNode.asText();
        }
        return jsonNode.toString();
    }

    /**
     * @param json
     * @param jsonPath
     * @return
     * @see https://github.com/json-path/JsonPath
     */
    public static String jsonPath(String json, String jsonPath) {
        return JsonPath.read(json, jsonPath);
    }


    /**
     * 判断Key是否是数组类型
     *
     * @param key 键
     */
    public static boolean keyIsArray(String key) {
        return key.startsWith("[") && key.endsWith("]");
    }


    /**
     * 判断Json字符串是否是合法Json
     *
     * @param json Json字符串
     */
    public static boolean isJson(String json) {
        try {
            commonObjectMapper.readTree(json);
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    /**
     * Json转JsonNode
     *
     * @param json json对象
     */
    public static JsonNode getRoot(String json) {
        try {
            return commonObjectMapper.readTree(json);
        } catch (JsonProcessingException e) {
            log.error("getRoot.e", e);
            throw new RuntimeException("Json:" + json + "解析异常!");
        }
    }

    /**
     * 获取数组Key的索引
     *
     * @param key 数组键
     */
    public static int getArrayKeyValue(String key) {
        if (keyIsArray(key)) {
            String substring = key.substring(1, key.length() - 1);
            int i = Integer.parseInt(substring);
            if (i < 0) {
                throw new RuntimeException("Key:" + key + "下表不能小于0!");
            }
            return i;
        }
        throw new RuntimeException("Key:" + key + "不是数组类型!");
    }


    /**
     * 判断获取的值是否为空
     *
     * @param value 值
     */
    public static boolean isEmpty(String value) {
        if (StringUtils.isEmpty(value)) {
            return true;
        }
        if (StringUtils.equals(value, "[]")) {
            return true;
        }
        if (StringUtils.equals(value, "{}")) {
            return true;
        }
        return StringUtils.equals(value, "null");
    }


    /**
     * 对象转Json,忽略空值
     *
     * @param object 对象
     */
    public static String toJsonIgnoreNull(Object object) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return toJson(objectMapper, object);
    }


    /**
     * 对象转Json
     *
     * @param objectMapper 转Json操作类
     * @param object       对象
     */
    public static String toJson(ObjectMapper objectMapper, Object object) {
        try {
            return objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.error("对象转Json异常:{}", object, e);
            throw new RuntimeException("转Json异常!", e);
        }
    }


    /**
     * JavaType
     */
    public static JavaType toJavaType(Type type) {
        return commonObjectMapper.constructType(type);
    }

    public static <T> CollectionType toListType(Class<T> tClass) {
        return commonObjectMapper.getTypeFactory().constructCollectionType(List.class, tClass);
    }

}
